#include "cv_object.hpp"

#include "common.hpp"
#include "cv_common.hpp"
#include "opencv2/opencv.hpp"
#include "spdlog/spdlog.h"

Face::Face() {
  waring_ = false;
  SPDLOG_TRACE("Constructed.");
}

Face::Face(const cv::Rect2i& left, const cv::Rect2i& right) {
  waring_ = false;

  if (left.x > right.x) {
    left_eye_ = right;
    right_eye_ = left;
  } else {
    left_eye_ = left;
    right_eye_ = right;
  }
  auto left_center = component::AutoCenter(left_eye_);
  auto right_center = component::AutoCenter(right_eye_);
  auto height = std::min(left_eye_.height, right_eye_.height);
  cv::Rect2i rect(cv::Point2i(left_center.x, left_center.y + height),
                  cv::Point2i(right_center.x, right_center.y + 3 * height));
  if (rect.x < 0) rect.x = 0;
  if (rect.y < 0) rect.y = 0;
  if (rect.br().x >= 640) rect.width = 639 - rect.x;
  if (rect.br().y >= 480) rect.height = 479 - rect.y;
  roi_ = rect;
}

const cv::Rect2i& Face::GetRoi() {
  SPDLOG_DEBUG("roi : {}, {}, {}, {}", roi_.tl().x, roi_.tl().y, roi_.br().x,
               roi_.br().y);
  return roi_;
}

double Face::LightJudge(cv::Mat gray) {
  gray = gray(roi_);
  int sum = 0;

  if (gray.channels() != 1) {
    Expr exp = Error::kFRAME_ERROR;
    SPDLOG_ERROR("{} : channnels > 1", exp.What());
    return 0;
  }

  for (int row = 0; row < roi_.height; row++) {
    const uchar* ptr = gray.ptr(row);
    for (int col = 0; col < roi_.width; col++) {
      sum += ptr[0];
      ptr++;
    }
  }
  sum /= 255;
  if (sum > 0.7) waring_ = true;
  return sum;
}

void Face::Draw(const cv::Mat& output, const cv::Scalar& color,
                bool add_lable) {
  cv::rectangle(output, roi_, color, 2);
  cv::rectangle(output, left_eye_, painting::kBLUE, 2);
  cv::rectangle(output, right_eye_, painting::kBLUE, 2);
  auto right_center = component::AutoCenter(right_eye_);
  auto left_center = component::AutoCenter(left_eye_);
  cv::line(output, right_center, left_center, painting::kRED, 3);
  cv::line(output, (right_center + left_center) / 2,
           component::AutoCenter(roi_), painting::kRED, 3);

  std::string str = waring_ ? "NoMask" : "Mask";

  if (add_lable) {
    cv::putText(output, str, component::AutoCenter(roi_), painting::kCV_FONT,
                1.0, painting::kGREEN);
  }
}
